#include "common.fxh"
#include "ShadowMap.fxh"

uniform const float3 ambientLightColor = float3(0.9, 0.9, 0.9);   
uniform const float3 diffuseLightColor = float3(0,0, 0);   
uniform const float3 specularLightColor= float3(0, 0, 0);     
uniform const float Ilumination = 1;                    
uniform const float specularPower = 50;
uniform const float specularIntensity = 5;
uniform const float ReflectionIntensiy = 0;
uniform const float RimIntensity = 0.0f;
uniform const float EmIntensity = 0.6;
uniform const float NoiceIntensity = 0.5;
uniform const float Rim_Start = 0.3f;
uniform const float Rim_End = 1.0f;
uniform const float2 SpeedUV1;
float3 Rim_Color = float3( 0.5, 0.5, 0.5);
uniform const float2 textureTiling = {1,1};




struct VertexInput
{
	float4 position		: POSITION0;
	float2 texCoord		: TEXCOORD0;
    float3 normal		: NORMAL0;
    float3 binormal     : BINORMAL0;	
    float3 tangent		: TANGENT0;
};


struct VertexOutput
{
	float4 Position			: POSITION0;
	float2 texCoord			: TEXCOORD0;
    float3 viewDirection	: TEXCOORD8;
    float3x3 tangentToWorld	: TEXCOORD3;
    float4 Depth : TEXCOORD6;
	float4 LightSpacePos1  : TEXCOORD2;
    float4 LightSpacePos2 : TEXCOORD7;
    float4 L : TEXCOORD1;
};





VertexOutput VertexShader( VertexInput input )
{
    VertexOutput output = (VertexOutput)0;
    float4x4 wvp = mul(mul(World, View), Projection);
    output.Position = mul(input.position, wvp);
    float4 worldPosition = mul(input.position, World);
    float4 viewPosition = mul(worldPosition, View);
    output.viewDirection = cameraPosition - worldPosition;
    
    output.LightSpacePos1 = mul(mul(input.position, World), lightViewProjection1);
    output.LightSpacePos2 = mul(mul(input.position, World), lightViewProjection2);
   
    
    output.Depth.x = output.Position.z;
    output.Depth.y = output.Position.w;
    output.Depth.z = output.Position.z / MaxDepth;
    output.Depth.w = ComputeFogFactor(length(cameraPosition - worldPosition),FogNear,FogFar);
    
    output.tangentToWorld[0] = mul(input.tangent,   World);
    output.tangentToWorld[1] = mul(input.binormal,  World);
    output.tangentToWorld[2] = mul(input.normal,    World);
    output.texCoord = input.texCoord;
    return output;
}


PixelShaderOutput PixelShader( VertexOutput input)
{
    PixelShaderOutput output;
    
	float2 texCoord = input.texCoord * textureTiling;
	input.viewDirection = normalize(input.viewDirection);
	
    float4 diffuseTexture = tex2D(DiffuseTextureSampler, texCoord);
    float4 Specmap = tex2D(SpecularTextureSampler, texCoord);
    float4 EM = tex2D(EmissiveTextureSampler, texCoord)* EmIntensity;
	float3 normalFromMap = normalize(input.tangentToWorld[2]);

    float3 SHandAm = SampleSH(normalFromMap)*ambientLightColor;
    float3 normalDir = normalize(Light1Direction);
	float3 diffuse = (max(dot(normalFromMap, normalDir), 0) * Light1Color);
    Rim_Color *= smoothstep(Rim_Start, Rim_End, 1 - dot(normalFromMap, input.viewDirection)) * RimIntensity;
	float rDotV1 = saturate(dot(reflect(-normalDir, normalFromMap), input.viewDirection));
    float3 SpecularSource = specularLightColor * pow(rDotV1, specularPower) * specularIntensity * Specmap;
 
 
    float3 diffuseLight = (SHandAm * Light1Color) + (diffuseLightColor * diffuse) * 1 + SpecularSource; 
	float3 FinalColor = ((diffuseTexture + Rim_Color) * Ilumination) + EM;
	
    output.Color.rgb = lerp(FinalColor,FogColor, input.Depth.w);
    output.Color.a = diffuseTexture.a;
    output.Normal.rgb = normalFromMap;
    output.Normal.a = input.Depth.z;
    output.Depth = input.Depth.x / input.Depth.y;
    output.Back.rgb = lerp(diffuseLight,FogColor, input.Depth.w);
    output.Back.a = 0;
    clip(diffuseTexture.a - 0.92);
    return output;
}



technique Full
{
    pass GO
    {
        CullMode = None;//CCW
        VertexShader = compile vs_3_0 VertexShader();
        PixelShader = compile ps_3_0 PixelShader();
    }
}

















VertexOutputShadow VertexShaderShadow(VertexInputShadow input)
{   
    VertexOutputShadow output = (VertexOutputShadow)0;
    output.Position = mul(input.position, mul(World, lightViewProjection));
    output.Depth.xy = output.Position.zw;
    output.texCoord = input.texCoord;
    return output;
}
PixelShaderShadowOutput PS_CreateShadowMap(VertexOutputShadow input)
{
    PixelShaderShadowOutput output;
	float2 texCoord = input.texCoord * textureTiling;
    float4 diffuseTexture = tex2D(DiffuseTextureSampler, texCoord);
    float4 outColor = float4(input.Depth.x / input.Depth.y, 1.0f, 1.0f, 1.0f);
    output.Depth = outColor;
    clip(diffuseTexture.a - 0.7);
    return output;
    
}
technique CreateShadowMap
{
    pass
    {
        VertexShader = compile vs_3_0 VertexShaderShadow();
        PixelShader = compile ps_3_0 PS_CreateShadowMap(); 
    }
}
